<script setup lang="ts">
import axios from 'axios';



type MessageType = 'text' | 'image' | 'audio' | 'video'

interface Message {
  id: string
  content: string
  type: MessageType
  timestamp: string
  fileUrl?: string
  fileName?: string
}

// 状态管理
const messages = ref<Message[]>([])
const ws = ref<WebSocket | null>(null)
const newMessage = ref('')
const uploadProgress = ref(0)
const showProgress = ref(false)
const isConnected = ref(false)
const reconnectAttempts = ref(0)
const maxReconnectAttempts = 5

const scrollContainer = ref(null)
function scrollToBottom() {
  if (scrollContainer.value) {
    // @ts-ignore
    scrollContainer.value.scrollTop = scrollContainer.value.scrollHeight
  }
}
watch(messages, async () => {
  console.log(12312)

  await nextTick() // 等待 DOM 更新
  scrollToBottom()
}, { deep: true })

const HEARTBEAT_INTERVAL = 25000 // 25秒（小于Nginx默认30秒）

// 修改connectWebSocket函数
const connectWebSocket = () => {
  // 清除旧连接
  if (ws.value?.readyState === WebSocket.OPEN) {
    ws.value.close(1000, '正常关闭')
  }

  ws.value = new WebSocket('/ws')
  let heartbeatTimer: NodeJS.Timeout
  let lastActivityTime = Date.now()

  // 添加活动检测
  const checkActivity = () => {
    if (Date.now() - lastActivityTime > HEARTBEAT_INTERVAL * 1.5) {
      ws.value?.close(1006, '活动超时')
    }
  }

  ws.value.onopen = () => {
    isConnected.value = true
    reconnectAttempts.value = 0
    lastActivityTime = Date.now()

    // 启动心跳和活动检测
    heartbeatTimer = setInterval(() => {
      if (ws.value?.readyState === WebSocket.OPEN) {
        ws.value.send(JSON.stringify({ type: 'PING' }))
        checkActivity()
      }
    }, HEARTBEAT_INTERVAL)
  }

  ws.value.onclose = (e) => {
    clearInterval(heartbeatTimer)
    // 仅异常关闭时触发重连
    if (e.code !== 1000) {
      isConnected.value = false
      if (reconnectAttempts.value < maxReconnectAttempts) {
        const delay = Math.min(1000 * Math.pow(2, reconnectAttempts.value), 30000)
        setTimeout(connectWebSocket, delay)
        reconnectAttempts.value++
      }
    }
  }

  ws.value.onerror = (err) => {
    console.error('WebSocket error:', err)
    ws.value?.close()
  }

  ws.value.onmessage = (event) => {
    const { type, data } = JSON.parse(event.data)

    if (type === 'PONG') return

    if (type === 'INIT') {
      messages.value = data.map((v: any) => ({
        ...v,
        fileUrl: v.fileUrl ? `/api${v.fileUrl}` : undefined
      }))
    } else if (type === 'NEW_MESSAGE') {
      messages.value.push({
        ...data,
        fileUrl: data.fileUrl ? `/api${data.fileUrl}` : undefined
      })
    }
  }
}

// 发送消息
const sendMessage = (msg: Message) => {
  if (ws.value?.readyState === WebSocket.OPEN) {
    ws.value.send(JSON.stringify(msg))
  } else {
    console.error('WebSocket is not open')
  }
}

const sendTextMessage = () => {
  if (!newMessage.value.trim()) return

  const msg: Message = {
    id: Date.now().toString(),
    content: newMessage.value,
    type: 'text',
    timestamp: new Date().toISOString()
  }

  sendMessage(msg)
  newMessage.value = ''
}

// 文件上传
const uploadFile = async (file: File) => {
  const formData = new FormData()
  formData.append('file', file)

  try {
    showProgress.value = true
    const res = await axios.post('/api/upload', formData, {
      onUploadProgress: (progressEvent) => {
        if (progressEvent.total) {
          uploadProgress.value = Math.round(
            (progressEvent.loaded * 100) / progressEvent.total
          )
        }
      }
    })

    const type = file.type.split('/')[0] as MessageType
    const msg: Message = {
      id: Date.now().toString(),
      content: file.name,
      type,
      timestamp: new Date().toISOString(),
      fileUrl: res.data.url,
      fileName: res.data.originalName
    }

    sendMessage(msg)
  } finally {
    setTimeout(() => {
      uploadProgress.value = 0
      showProgress.value = false
    }, 1000)
  }
}

const handleFileChange = (e: Event) => {
  const input = e.target as HTMLInputElement
  if (input.files?.length) {
    uploadFile(input.files[0])
    input.value = ''
  }
}

// 写入文本内容到剪贴板
function legacySyncToClipboard(text: string) {
  const textarea = document.createElement('textarea')
  textarea.value = text
  document.body.appendChild(textarea)
  textarea.select()

  try {
    const success = document.execCommand('copy')
    document.body.removeChild(textarea)
    alert('复制成功')

    return success
  } catch (err) {
    console.error('传统方式同步失败:', err)
    return false
  }
}

// 生命周期
connectWebSocket()

onUnmounted(() => {
  ws.value?.close()
})
</script>

<template>
  <div class="chat-container">
    <div class="connection-status" :class="{ connected: isConnected }">
      {{ isConnected ? '已连接' : '连接中...' }}
    </div>

    <div ref="scrollContainer" class="messages">
      <div v-for="msg in messages" :key="msg.id" class="message"
        @click="msg.type === 'text' ? legacySyncToClipboard(msg.content) : () => { }">
        <div class="time">{{ new Date(msg.timestamp).toLocaleString() }}</div>
        <div v-if="msg.type === 'text'">{{ msg.content }}</div>
        <img v-else-if="msg.type === 'image'" :src="msg.fileUrl" :alt="msg.fileName" />
        <audio v-else-if="msg.type === 'audio'" controls :src="msg.fileUrl" />
        <video v-else-if="msg.type === 'video'" controls :src="msg.fileUrl" />
        <a v-else-if="msg.type === 'application'" :href="msg.fileUrl">{{ msg.content }}</a>
      </div>
    </div>

    <div class="input-area">
      <input v-model="newMessage" @keyup.enter="sendTextMessage" :disabled="!isConnected" placeholder="输入消息..." />
      <button @click="sendTextMessage" :disabled="!isConnected">发送</button>
      <input type="file" @change="handleFileChange" accept="image/*,audio/*,video/*" :disabled="!isConnected" />

      <div v-if="showProgress" class="progress-bar">
        <div class="progress" :style="{ width: `${uploadProgress}%` }"></div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  max-width: 800px;
  margin: 0 auto;
  background: #f5f7fb;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

.connection-status {
  padding: 8px;
  text-align: center;
  background: #ff6b6b;
  color: white;
}

.connection-status.connected {
  background: #42b983;
}

.messages {
  flex: 1;
  padding: 20px;
  overflow-y: auto;
}

.message {
  margin-bottom: 16px;
  max-width: 70%;
  padding: 12px 16px;
  border-radius: 18px;
  background: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

video {
  width: 100px;
  height: 100px;
}

img {
  width: 100px;
  height: 100px;
}

.time {
  font-size: 12px;
  color: #333;
}

.input-area {
  padding: 16px;
  background: white;
  border-top: 1px solid #eaeaea;
  display: flex;
  gap: 10px;
  align-items: center;
}

.progress-bar {
  width: 100%;
  height: 5px;
  background: #eee;
  margin-top: 10px;
}

.progress {
  height: 100%;
  background: #42b983;
  transition: width 0.3s;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .chat-container {
    border-radius: 0;
  }

  .message {
    max-width: 85%;
  }
}
</style>
